// Growth-rate calculator
// Common defines for grate library.

#ifndef GRATE_UTIL_COMMON_H
#define GRATE_UTIL_COMMON_H

#include <stddef.h>
#include <stdint.h>
#include <string.h>

namespace growth_rate {

// Compile definitions.
#ifndef GRATE_DEBUG
# define GRATE_DEBUG 0
#endif

// Portability macro.
#if defined(__APPLE__)
# define GRATE_MACOSX 1
#else
# define GRATE_MACOSX 0
#endif

// Assertions.
void Abort();
void CheckFailed(const char *condition, const char *filename, int line_no);
#define CHECK(cond) do { if (!(cond)) { \
  CheckFailed(#cond, __FILE__, __LINE__); \
}}while(0);
#define CHECK_GT(a, b) CHECK((a) > (b))
#define CHECK_GE(a, b) CHECK((a) >= (b))
#define CHECK_EQ(a, b) CHECK((a) == (b))
#define CHECK_LE(a, b) CHECK((a) <= (b))
#define CHECK_LT(a, b) CHECK((a) < (b))

#if GRATE_DEBUG == 1
# define DCHECK(cond) CHECK(cond)
#else
# define DCHECK(cond)
#endif
#define DCHECK_GT(a, b) DCHECK((a) > (b))
#define DCHECK_GE(a, b) DCHECK((a) >= (b))
#define DCHECK_EQ(a, b) DCHECK((a) == (b))
#define DCHECK_LE(a, b) DCHECK((a) <= (b))
#define DCHECK_LT(a, b) DCHECK((a) < (b))

#define UNIMPLEMENTED() CHECK("unimplemented" && false)

// Convenience macro.
#define ARRAYSIZE(a) ((sizeof(a))/(sizeof(a[0])))

// Memory allocation.
uint64_t PhysicalMemory();
void* Malloc(size_t size);
void Free(void *p);
void *Realloc(void *p, size_t size);

template <typename T>
T* AllocateArray(size_t length) {
  void* mem = Malloc(sizeof(T) * length);
  CHECK(mem);
  return reinterpret_cast<T*>(mem);
}

template <typename T>
void FreeArray(T** arr) {
  CHECK(arr);
  if (*arr != 0)
    Free(*arr);
  *arr = 0;
}

template <typename T>
void ReallocateArray(T** arr, size_t new_length) {
  CHECK(arr);
  void *mem = Realloc(*arr, sizeof(T) * new_length);
  CHECK(mem);
  *arr = reinterpret_cast<T*>(mem);
}

template <typename T>
class ScopedArray {
 public:
  // Scoped array may be initialized late.
  ScopedArray() : arr_(0), length_(0) { }
  explicit ScopedArray(size_t length) : arr_(0), length_(length) {
    initialize(length_);
  }
  void initialize(size_t length) {
    CHECK_EQ(0, arr_);
    arr_ = AllocateArray<T>(length);
    length_ = length;
  }
  ~ScopedArray() {
    FreeArray(&arr_);
  }
  T* data() {
    CHECK(arr_);
    return arr_;
  }
  T& operator[] (size_t index) {
    DCHECK_LT(index, length_);
    return arr_[index];
  }
  const T& operator[] (size_t index) const {
    DCHECK_LT(index, length_);
    return arr_[index];
  }
  void clear() {
    CHECK(arr_);
    memset(arr_, 0, sizeof(arr_[0]) * length_);
  }
  size_t length() const { return length_; }

 private:
  T* arr_;
  size_t length_;
};

template <typename T>
class AutoObjectDeleter {
 public:
  explicit AutoObjectDeleter(T* obj) : obj_(obj) { }
  ~AutoObjectDeleter() { delete obj_; }
 private:
  T* obj_;
};

// Basic math functions.
template <typename T>
T Min(const T& a, const T& b) { return (a < b) ? a : b; }
template <typename T>
T Max(const T& a, const T& b) { return (a > b) ? a : b; }

bool IsPowerOfTwo(size_t x);
size_t Log2(size_t x);
size_t RoundUpToPowerOfTwo(size_t x);

// Auxiliary enums.
enum Direction {
  Backward = -1,
  Forward = 1
};

// Common constants.
extern const size_t kBitsInByte;

// Logging and output.
void SetReportFile(const char *filename);
void DebugReport(const char *msg, ...);
void Report(const char *msg, ...);

}  // namespace growth_rate

#endif  // GRATE_UTIL_COMMON_H
